home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / filesyst / dosfs / dmsdosfs.000 / dmsdosfs / dmsdosfs-0.6.9b / dmsdos_compr.c < prev    next >
C/C++ Source or Header  |  1996-07-29  |  14KB  |  484 lines

  1. /*
  2.  
  3. linux/fs/dmsdos/dmsdos_compr.c
  4.  
  5. DMSDOS filesystem: compression routines
  6.  
  7. ******************************************************************************
  8. DMSDOS (Doublespace/Drivespace compressed MSDOS filesystem) for Linux
  9. written 1995,1996 by Frank Gockel
  10.  
  11.     (C) Copyright 1995,1996 by Frank Gockel
  12.  
  13. Some code of the dmsdos filesystem has been copied from the msdos filesystem
  14. so there are the following additional copyrights:
  15.  
  16.     (C) Copyright 1992,1993 by Werner Almesberger (msdos filesystem)
  17.     (C) Copyright 1994,1995 by Jacques Gelinas (mmap code)
  18.     (C) Copyright 1992-1995 by Linus Torvalds
  19.  
  20. The DMSDOS filesystem was inspired by the THS filesystem (a simple doublespace
  21. DS-0-2 compressed read-only filesystem) written 1994 by Thomas Scheuermann.
  22.  
  23. The DMSDOS filesystem is distributed under the Gnu General Public Licence.
  24. See file COPYING for details.
  25. ******************************************************************************
  26.  
  27. */
  28.  
  29. #include <linux/errno.h>
  30. #include <linux/kernel.h>
  31. #include <linux/malloc.h>
  32. #include <linux/fs.h>
  33. #include <linux/msdos_fs.h>
  34. #include <linux/dmsdos_fs.h>
  35.  
  36. /* undef this to avoid compression */
  37. #define DBL_COMPRESSION
  38.  
  39. /* GUESS_HACK forces the compression scheme guessing code to return JM-0-1 as
  40.    result when it in fact has guessed SQ-0-0. This is because SQ-0-0 is
  41.    currently unsupported, so write access would be always uncompressed on
  42.    SQ-0-0 compressed drives. 'undef' this to avoid this hack */ 
  43. #define GUESS_HACK
  44.  
  45. #ifdef __KERNEL__
  46. extern Dblsb dblsb[];
  47. #else
  48. extern int cfaktor;
  49. void panic(char*);
  50. #endif /*__KERNEL__*/
  51.  
  52. /* maybe the values have to be adapted for optimal compression/speed 
  53.    relationship */
  54. int c_maxdiff[12]={ 63, 63, 63, 63,319,319,319,319,4414,4414,4414,4414};
  55. int c_maxlen[12] ={ 64,128,256,512, 64,128,256,512,  64, 128, 256, 512};
  56.  
  57. inline void putbit(unsigned char*clusterk,int*zielpos,int*zielmask,int bit)
  58. {
  59.   if(bit)clusterk[*zielpos]|=*zielmask;
  60.   else clusterk[*zielpos]&=~(*zielmask);
  61.   (*zielmask)<<=1;
  62.   if(*zielmask==256)
  63.   { *zielmask=1;
  64.     ++(*zielpos);
  65.   }
  66. }
  67.  
  68. void putbits(unsigned char*clusterk,int*zielpos,int*zielmask,int byte,int anz)
  69. { int i;
  70.   int mask;
  71.   
  72.   mask=1;
  73.   for(i=0;i<anz;++i)
  74.   { putbit(clusterk,zielpos,zielmask,byte&mask);
  75.     mask<<=1;
  76.   }
  77. }
  78.  
  79. void write_byte(unsigned char*clusterk,int*zielpos,int*zielmask,int byte,
  80.                 int method)
  81. { if(method!=JM_0_0&&method!=JM_0_1)
  82.   { if(byte<128)putbits(clusterk,zielpos,zielmask,2,2);
  83.     else putbits(clusterk,zielpos,zielmask,1,2);
  84.   }
  85.   else /* JM_0_0 */
  86.   { if(byte<128)putbit(clusterk,zielpos,zielmask,0);
  87.     else putbits(clusterk,zielpos,zielmask,3,2);
  88.   }
  89.   putbits(clusterk,zielpos,zielmask,byte,7);
  90. }
  91.  
  92. void write_temp(unsigned char*clusterk,int*zielpos,int*zielmask,
  93.                 unsigned char*tempstr,int len,int diff,int method)
  94. { if(len==1)
  95.   { write_byte(clusterk,zielpos,zielmask,tempstr[0],method);
  96.     return;
  97.   }
  98.   if(len==2&&(method==JM_0_0||method==JM_0_1))
  99.   { write_byte(clusterk,zielpos,zielmask,tempstr[0],method);
  100.     write_byte(clusterk,zielpos,zielmask,tempstr[1],method);
  101.     return;
  102.   }
  103.   if(method!=JM_0_0&&method!=JM_0_1)
  104.   { ++len; /* corrects different counting scheme */
  105.     if(diff<64)putbits(clusterk,zielpos,zielmask,0,2);
  106.     else putbits(clusterk,zielpos,zielmask,3,2);
  107.   }
  108.   else /* JM_0_0 */
  109.   { putbits(clusterk,zielpos,zielmask,1,2);
  110.     putbit(clusterk,zielpos,zielmask,(diff<64)?0:1);
  111.   }
  112.   if(diff<64)putbits(clusterk,zielpos,zielmask,diff,6);
  113.   else 
  114.   { if(diff<320)
  115.     { putbit(clusterk,zielpos,zielmask,0);
  116.       putbits(clusterk,zielpos,zielmask,diff-64,8);
  117.     }
  118.     else
  119.     { putbit(clusterk,zielpos,zielmask,1);
  120.       putbits(clusterk,zielpos,zielmask,diff-320,12);
  121.     }
  122.   }
  123.   /* okay, now encode len */
  124.   if(len==3)
  125.   { putbit(clusterk,zielpos,zielmask,1);
  126.     return;
  127.   }
  128.   putbit(clusterk,zielpos,zielmask,0);
  129.   if(len<6)
  130.   { putbit(clusterk,zielpos,zielmask,1);
  131.     putbit(clusterk,zielpos,zielmask,len-4);
  132.     return;
  133.   }
  134.   putbit(clusterk,zielpos,zielmask,0);
  135.   if(len<10)
  136.   { putbit(clusterk,zielpos,zielmask,1);
  137.     putbits(clusterk,zielpos,zielmask,len-6,2);
  138.     return;
  139.   }
  140.   putbit(clusterk,zielpos,zielmask,0);
  141.   if(len<18)
  142.   { putbit(clusterk,zielpos,zielmask,1);
  143.     putbits(clusterk,zielpos,zielmask,len-10,3);
  144.     return;
  145.   }
  146.   putbit(clusterk,zielpos,zielmask,0);
  147.   if(len<34)
  148.   { putbit(clusterk,zielpos,zielmask,1);
  149.     putbits(clusterk,zielpos,zielmask,len-18,4);
  150.     return;
  151.   }
  152.   putbit(clusterk,zielpos,zielmask,0);
  153.   if(len<66)
  154.   { putbit(clusterk,zielpos,zielmask,1);
  155.     putbits(clusterk,zielpos,zielmask,len-34,5);
  156.     return;
  157.   }
  158.   putbit(clusterk,zielpos,zielmask,0);
  159.   if(len<130)
  160.   { putbit(clusterk,zielpos,zielmask,1);
  161.     putbits(clusterk,zielpos,zielmask,len-66,6);
  162.     return;
  163.   }
  164.   putbit(clusterk,zielpos,zielmask,0);
  165.   if(len<258)
  166.   { putbit(clusterk,zielpos,zielmask,1);
  167.     putbits(clusterk,zielpos,zielmask,len-130,7);
  168.     return;
  169.   }
  170.   putbit(clusterk,zielpos,zielmask,0);
  171.   putbit(clusterk,zielpos,zielmask,1);
  172.   putbits(clusterk,zielpos,zielmask,len-258,8);
  173. }
  174.  
  175. void write_marker(unsigned char*clusterk,int*zielpos,int*zielmask,int method)
  176. { if(method==JM_0_0||method==JM_0_1)putbits(clusterk,zielpos,zielmask,13,4);
  177.   else /* DS_0_x */ putbits(clusterk,zielpos,zielmask,7,3);
  178.   putbits(clusterk,zielpos,zielmask,0xFFF,12); 
  179. }
  180.  
  181. inline int such_rb_byte(unsigned char*clusterd, int byte, int ab)
  182. { while(ab>=0)
  183.   { if(byte==clusterd[ab])return ab;
  184.     --ab;
  185.   }
  186.   return -1;
  187. }
  188.  
  189. inline int mystrncmp(unsigned char*a,unsigned char*b,int len)
  190. { --len;
  191.   while(len>=0)
  192.   { if(a[len]!=b[len])return 1;
  193.     --len;
  194.   }
  195.   return 0;
  196. }
  197.  
  198. inline int such_rb_string(unsigned char*clusterd,unsigned char*tempstr,int ab,
  199.                    int len)
  200. { while(ab>=0)
  201.   { if(mystrncmp(tempstr,&(clusterd[ab]),len)==0)return ab;
  202.     --ab;
  203.   }
  204.   return -1;
  205. }                   
  206.  
  207. /* compresses a cluster 
  208.    gets uncompressed size (number of used sectors)
  209.    returns compressed size (in number of used sectors) or -1 if failed
  210. */
  211. int compress(unsigned char* clusterk, unsigned char* clusterd, int size,
  212.              int method,int cvfnr)
  213.  
  214. #ifdef DBL_COMPRESSION
  215.  
  216.   int i;
  217.   int j;
  218.   int zielpos;
  219.   int zielmask;
  220.   int pos;
  221.   int lentemp;
  222.   int maxzielpos;
  223.   int byte;
  224.   int rb_pos=0; /* avoids warning */
  225.   int rb_beg=0; /* avoids warning */
  226.   int last_rb_pos;
  227. #ifdef __KERNEL__
  228.   int maxdiff=c_maxdiff[dblsb[cvfnr].s_cfaktor];
  229.   int maxlen=c_maxlen[dblsb[cvfnr].s_cfaktor];
  230. #else
  231.   int maxdiff=c_maxdiff[cfaktor];
  232.   int maxlen=c_maxlen[cfaktor];
  233. #endif /*__KERNEL__*/
  234.  
  235.   switch(method)
  236.   { case DS_0_0:
  237.     case DS_0_1:
  238.     case DS_0_2: /* handled together with JM_0_0 because similar */
  239.     case JM_0_0:
  240.     case JM_0_1:
  241.  
  242.       zielpos=0;
  243.       zielmask=1;
  244.       pos=0;
  245.       lentemp=0;
  246.       maxzielpos=(size-1)*512;
  247.       
  248.       /* put magic number */
  249.       putbits(clusterk,&zielpos,&zielmask,method,32);
  250.       
  251.       for(i=0;i<size;++i)
  252.       { for(j=0;j<512;++j)
  253.         { byte=clusterd[i*512+j];
  254.         
  255.           /* begin compression algorithm (sorry for using gotos...) */
  256.           
  257.           retry:
  258.             if(pos==0) /* hmm... first byte, nothing to compress */
  259.             { write_byte(clusterk,&zielpos,&zielmask,byte,method);
  260.               ++pos;
  261.               goto end;
  262.             }
  263.             
  264.             if(lentemp==0)
  265.             { rb_pos=such_rb_byte(clusterd,byte,pos-1);
  266.               if(rb_pos<0||pos-rb_pos>maxdiff)
  267.               { write_byte(clusterk,&zielpos,&zielmask,byte,method);
  268.                 ++pos;
  269.                 goto end;
  270.               }
  271.               rb_beg=pos;
  272.               lentemp=1;
  273.               ++pos;
  274.               goto end;
  275.             }
  276.             
  277.             else
  278.             { ++lentemp;
  279.               if(lentemp+rb_pos>rb_beg) goto norb;
  280.               if(byte!=clusterd[rb_pos+lentemp-1]) goto norb;
  281.               if(lentemp==maxlen)
  282.               { write_temp(clusterk,&zielpos,&zielmask,&(clusterd[rb_beg]),
  283.                            lentemp,rb_beg-rb_pos,method);
  284.                 lentemp=0;
  285.               }
  286.               ++pos;
  287.               goto end;
  288.               
  289.             norb:
  290.               last_rb_pos=rb_pos;
  291.               rb_pos=such_rb_string(clusterd,&(clusterd[rb_beg]),
  292.                                     rb_beg-lentemp,lentemp);
  293.               if(rb_pos<0||rb_beg-rb_pos>maxdiff)
  294.               { --lentemp;
  295.                 write_temp(clusterk,&zielpos,&zielmask,&(clusterd[rb_beg]),
  296.                            lentemp,rb_beg-last_rb_pos,method);
  297.                 lentemp=0;
  298.                 goto retry;
  299.               }
  300.               ++pos;
  301.             }
  302.             
  303.           /* end compression algorithm */
  304.           
  305.           end:
  306.             if(zielpos>maxzielpos)return -1; /* incompressible data */
  307.           
  308.         }
  309.         if(lentemp>0)
  310.         { write_temp(clusterk,&zielpos,&zielmask,&(clusterd[rb_beg]),
  311.                      lentemp,rb_beg-rb_pos,method);
  312.           lentemp=0;
  313.         }
  314.         write_marker(clusterk,&zielpos,&zielmask,method);
  315.       }
  316.       
  317.       if(zielpos>maxzielpos)return -1;
  318.       if(zielmask!=1)++zielpos; /* last byte is only used if mask != 1 */
  319.       return (zielpos-1)/512+1;
  320.       
  321.     default: 
  322.       /* sorry, other compression methods currently not available */
  323.       return -1; 
  324.   }
  325.   
  326. #endif
  327.  
  328.   return -1;
  329. }
  330.  
  331. /* write a dmsdos cluster, compress before if possible;
  332.    length is the number of used bytes, may be < SECTOR_SIZE*sectperclust only
  333.    in the last cluster of a file;
  334.    cluster must be allocated by allocate_cluster before if it is a new one;
  335.    unable to write dir clusters;
  336.    to avoid MDFAT level fragmentation, near_sector should be the sector no
  337.    of the preceeding cluster;
  338.    if ucflag>0 uncompressed write is forced (only for umsdos --linux-.---)
  339.    if ucflag<0 raw write is forced with compressed size -ucflag (in sectors).
  340. */
  341.  
  342. #ifdef __KERNEL__
  343.  
  344. int dmsdos_write_cluster(struct super_block*sb,
  345.                          unsigned char* clusterd, int length, int clusternr,
  346.                          int near_sector, int cvfnr, int ucflag)
  347. { int method;
  348.   unsigned char* clusterk;
  349.   int size;
  350.   Mdfat_entry mde;
  351.   int sektor;
  352.   int i;
  353.   int res;
  354.   int ksize;
  355.   struct buffer_head*bh;
  356.  
  357.   LOCK_READWRITE;  
  358.   /*printk("DMSDOS write_cluster clusternr=%d length=%d near_sector=%d cvfnr=%d\n",
  359.          clusternr,length,near_sector,cvfnr);*/
  360.  
  361.   /* guess compression method if not already known */
  362.   if(dblsb[cvfnr].s_comp==GUESS)
  363.   { 
  364.     printk("DMSDOS: write_cluster: guessing compression method...\n");
  365.     for(i=2;i<=dblsb[cvfnr].s_max_cluster;++i)
  366.     { dbl_mdfat_value(sb,i,cvfnr,NULL,&mde);
  367.       /*if((mdfat&0xC0000000)==0x80000000)*/
  368.       if(mde.flags==2)
  369.       { bh=read_dbl_sector(sb,mde.sector_minus_1+1,cvfnr);
  370.         if(bh!=NULL)
  371.         {
  372.           res=CHL(bh->b_data);
  373.           bh_free(sb,bh);
  374.           if(res==DS_0_0){dblsb[cvfnr].s_comp=DS_0_0;goto guess_ok;}
  375.           if(res==DS_0_1){dblsb[cvfnr].s_comp=DS_0_1;goto guess_ok;}
  376.           if(res==DS_0_2){dblsb[cvfnr].s_comp=DS_0_2;goto guess_ok;}
  377.           if(res==JM_0_0){dblsb[cvfnr].s_comp=JM_0_0;goto guess_ok;}
  378.           if(res==JM_0_1){dblsb[cvfnr].s_comp=JM_0_1;goto guess_ok;}
  379.           if(res==SQ_0_0){dblsb[cvfnr].s_comp=SQ_0_0;goto guess_ok;}
  380.         }
  381.       }
  382.     }
  383.     printk("DMSDOS: could not guess compression method for CVF %d\n",cvfnr+1);
  384.     dblsb[cvfnr].s_comp=UNCOMPRESSED;
  385.     
  386.     guess_ok:
  387.     printk("DMSDOS: write_cluster: guessed 0x%08x.\n",dblsb[cvfnr].s_comp);
  388. #ifdef GUESS_HACK
  389.     if(dblsb[cvfnr].s_comp==SQ_0_0)
  390.     { dblsb[cvfnr].s_comp=JM_0_1;
  391.       printk("DMSDOS: guess_hack: guessed SQ-0-0 not supported, using JM-0-1 instead.\n");
  392.     }
  393. #endif
  394.   }
  395.   
  396.   method=dblsb[cvfnr].s_comp; /* default compression method */
  397.   
  398.   size=(length-1)/512+1;
  399.   if(size==1||ucflag!=0)method=UNCOMPRESSED; /* will not become smaller */
  400.   
  401.   if(method==UNCOMPRESSED) /* includes RAW write */
  402.   { clusterk=clusterd;
  403.     if(ucflag<0)
  404.     { /* raw write of already compressed data (for dmsdosd/ioctl) */
  405.       ksize=-ucflag;
  406.       mde.size_lo_minus_1=ksize-1;
  407.       mde.size_hi_minus_1=size-1;
  408.       mde.flags=2;
  409.     }
  410.     else
  411.     { /* normal uncompressed write */
  412.       /*mdfat=0xC0000000|((size-1)<<26)|((size-1)<<22);*/
  413.       mde.size_lo_minus_1=size-1;
  414.       mde.size_hi_minus_1=size-1;
  415.       mde.flags=3;
  416.       ksize=size;
  417.     }
  418.   }
  419.   else
  420.   { if(try_daemon(clusternr,cvfnr,length,method))goto wr_uc;
  421.     clusterk=(unsigned char*)MALLOC(size*SECTOR_SIZE);
  422.     if(clusterk==NULL)
  423.     { printk("DMSDOS: write_cluster: no memory for compression, writing uncompressed!\n");
  424.   wr_uc:  
  425.       clusterk=clusterd;
  426.       /*mdfat=0xC0000000|((size-1)<<26)|((size-1)<<22);*/
  427.       mde.size_lo_minus_1=size-1;
  428.       mde.size_hi_minus_1=size-1;
  429.       mde.flags=3;
  430.       method=UNCOMPRESSED;
  431.       ksize=size;
  432.     }
  433.     else 
  434.     { /*printk("DMSDOS: write_cluster: compressing...\n");*/
  435.       ksize=compress(clusterk,clusterd,size,method,cvfnr);
  436.       /*printk("DMSDOS: write cluster: compressing finished\n");*/
  437.       if(ksize<0)
  438.       { /* compression failed */
  439.         FREE(clusterk);
  440.         clusterk=clusterd;
  441.         /*mdfat=0xC0000000|((size-1)<<26)|((size-1)<<22);*/
  442.         mde.size_lo_minus_1=size-1;
  443.         mde.size_hi_minus_1=size-1;
  444.         mde.flags=3;
  445.         method=UNCOMPRESSED;
  446.         ksize=size;
  447.       }
  448.       else
  449.       { /*mdfat=0x80000000|((size-1)<<26)|((ksize-1)<<22);*/
  450.         mde.size_lo_minus_1=ksize-1;
  451.         mde.size_hi_minus_1=size-1;
  452.         mde.flags=2;
  453.       }
  454.     }
  455.   }
  456.   
  457.   /*printk("DMSDOS: write_cluster: call replace_existing_cluster mdfat=0x%x\n",
  458.          mdfat);*/
  459.   sektor=replace_existing_cluster(sb,clusternr,near_sector,&mde,cvfnr);
  460.   /*printk("DMSDOS: write_cluster: replace_existing_cluster returned %d\n",
  461.          sektor);*/
  462.   if(sektor<0)res=-ENOSPC;
  463.   else
  464.   { res=0;
  465.     for(i=0;i<ksize;++i)
  466.     { bh=noread_dbl_sector(sb,sektor+i,cvfnr);
  467.       if(bh==NULL)res=-EIO;
  468.       else
  469.       {
  470.         memcpy(bh->b_data,&(clusterk[SECTOR_SIZE*i]),SECTOR_SIZE);
  471.         bh_dirty(sb,bh);
  472.         bh_free(sb,bh);
  473.       }
  474.     }
  475.   }
  476.   
  477.   if(method!=UNCOMPRESSED)FREE(clusterk);
  478.   
  479.   UNLOCK_READWRITE;
  480.   return res;
  481. }
  482.  
  483. #endif /*__KERNEL__*/